package cn.tedu.mall.seckill.service.impl;

import cn.tedu.mall.pojo.product.vo.SkuStandardVO;
import cn.tedu.mall.pojo.seckill.model.SeckillSku;
import cn.tedu.mall.pojo.seckill.model.SeckillSpu;
import cn.tedu.mall.pojo.seckill.vo.SeckillSkuVO;
import cn.tedu.mall.product.service.seckill.IForSeckillSkuService;
import cn.tedu.mall.seckill.mapper.SeckillSkuMapper;
import cn.tedu.mall.seckill.mapper.SeckillSpuMapper;
import cn.tedu.mall.seckill.service.ISeckillSkuService;
import cn.tedu.mall.seckill.utils.SeckillCacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.RandomUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class SeckillSkuServiceImpl implements ISeckillSkuService {

    @Autowired
    private SeckillSkuMapper seckillSkuMapper;
    // dubbo调用product查询sku常规信息
    @DubboReference
    private IForSeckillSkuService dubboSkuService;
    // 需要将sku对象保存到Redis
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public List<SeckillSkuVO> listSeckillSkus(Long spuId) {
        // 执行查询,根据spuId 查询sku列表
        List<SeckillSku> seckillSkus=seckillSkuMapper
                                .findSeckillSkusBySpuId(spuId);
        // 实例化返回值类型的泛型集合用于后续返回
        // SeckillSkuVO是既包含秒杀信息,又包含常规信息的sku对象
        List<SeckillSkuVO> seckillSkuVOs=new ArrayList<>();
        // 遍历根据spuId查询出的sku集合
        for(SeckillSku sku : seckillSkus){
            // 获取skuId,后面会多次用到
            Long skuId=sku.getSkuId();
            // 获取sku对应的key
            String skuVOKey= SeckillCacheUtils.getSeckillSkuVOKey(skuId);
            // 声明SeckillSkuVO对象用于添加到集合中
            SeckillSkuVO seckillSkuVO=null;
            // 判断Redis中是否包含这个Key
            if(redisTemplate.hasKey(skuVOKey)){
                seckillSkuVO= (SeckillSkuVO) redisTemplate
                                    .boundValueOps(skuVOKey).get();
            }else{
                // 如果Redis中不存在这个key,就需要连接数据库查询了
                // 利用dubbo查询指定skuId的常规信息
                SkuStandardVO skuStandardVO = dubboSkuService.getById(skuId);
                // 常规信息和秒杀信息都具备了,准备为seckillSkuVO赋值
                // 首先还是先实例化
                seckillSkuVO=new SeckillSkuVO();
                BeanUtils.copyProperties(skuStandardVO,seckillSkuVO);
                // 秒杀信息手动赋值
                seckillSkuVO.setSeckillPrice(sku.getSeckillPrice());
                seckillSkuVO.setStock(sku.getSeckillStock());
                seckillSkuVO.setSeckillLimit(sku.getSeckillLimit());
                // 将赋好常规信息和秒杀信息的seckillSkuVO对象,保存到Redis中
                redisTemplate.boundValueOps(skuVOKey).set(
                        seckillSkuVO,
                        1000*60*5+ RandomUtils.nextInt(10000),
                        TimeUnit.MILLISECONDS);
            }
            // 在if-else结构结束之后,seckillSkuVO对象是一定有值的
            // 将它保存到seckillSkuVOs集合中
            seckillSkuVOs.add(seckillSkuVO);
        }
        // 返回集合seckillSkuVOs!!!
        return seckillSkuVOs;
    }
}







